﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Speech.Recognition;

namespace CodeTalk.CTSpeechCommands
{
    class CSInsertGeneric : SpeechCommand
    {
        private string[] genericTypes = null;
        private string[] nonGenericTypes = null;

        internal override GrammarBuilder GrammarBld(Context context, Context[] libraries)
        {
            if (context == null)
            {
                genericTypes = new string[] { };
                return null;
            }
            List<CodeSymbol> allSymbols = new List<CodeSymbol>(context.Symbols);
            foreach (var lib in libraries)
                allSymbols.AddRange(lib.Symbols);
            
            Choices nonGenericSymbolChoices = new Choices();
            List<string> spokenNonGenericTypes = new List<string>();
            foreach (var s in allSymbols)
            {
                if (s.Category == SymbolCategory.Type && s.Parameters == 0)
                {
                    nonGenericSymbolChoices.Add(new SemanticResultValue(s.SpokenForm, (int)s.SymbolID));
                    spokenNonGenericTypes.Add(s.SpokenForm);
                }
            }
            nonGenericTypes = spokenNonGenericTypes.ToArray();

            Choices genericSymbolChoices = new Choices();
            List<string> spokenTypes = new List<string>();
            int nChoices = 0;
            foreach (var gs in allSymbols)
            {
                if (gs.Category == SymbolCategory.Type && gs.Parameters > 0)
                {
                    spokenTypes.Add(gs.SpokenForm);
                    nChoices++;

                    GrammarBuilder genGB = new GrammarBuilder(gs.SpokenForm);
                    genGB.Append("of");
                    genGB.Append(new SemanticResultKey("p0", nonGenericSymbolChoices));
                    for (int i = 1; i < gs.Parameters; i++)
                    {
                        genGB.Append("comma");
                        genGB.Append(new SemanticResultKey("p" + i, nonGenericSymbolChoices));
                    }

                    genericSymbolChoices.Add(new SemanticResultValue(genGB, (int)gs.SymbolID));
                }
            }
            GrammarBuilder gb = new GrammarBuilder();
            gb.Append(new SemanticResultKey("generic", genericSymbolChoices));
            genericTypes = spokenTypes.ToArray();
            if (nChoices != 0)
                return gb;
            else
                return null;
        }

        public override string Name
        {
            get { return "Insert generic type"; }
        }

        public override string Description
        {
            get { return Name; }
        }

        public override string GetAlternativesFeedback(string recognizedText, SemanticValue semValue)
        {
            return recognizedText;
        }

        internal override bool CanSpokenFormMatch(string spokenForm)
        {
            foreach (var t in genericTypes)
            {
                if (spokenForm.StartsWith(t + " of ") && spokenForm.Length > t.Length + 4)
                    return true;
            }
            return false;
        }

        internal override object Execute(SpeechMode callingMode, string recognizedText, SemanticValue semValue)
        {
            SemanticValue genericSemantic = semValue["generic"];
            CodeSymbol symbol = callingMode.GetSymbolWithIDFromAnyLibraryUsed((uint)((int)genericSemantic.Value));

            //CodeSymbol symbol = callingMode.CurrentContext.GetSymbolWithID((uint)((int)genericSemantic.Value));
            string textToWrite = symbol.WrittenForm + "<";
            for (int i = 0; i < symbol.Parameters; i++)
            {
                CodeSymbol subsymbol = callingMode.GetSymbolWithIDFromAnyLibraryUsed((uint)((int)genericSemantic["p" + i].Value));
                if (i == symbol.Parameters - 1)
                    textToWrite += subsymbol.WrittenForm + "> ";
                else
                    textToWrite += subsymbol.WrittenForm + ", ";
            }
            callingMode.CurrentOutputHandler.SendKeys(textToWrite);
            string undoString = "^z^z^z";
            for (int i = 0; i < symbol.Parameters; i++)
                undoString += "^z^z";
            return undoString;
        }
    }
}
